package com.zhuoan.im.webapp.controller.server;

import com.jfinal.kit.PropKit;
import com.zhuoan.im.server.expandprocessor.ImWsHandshakeProcessor;
import com.zhuoan.im.server.handler.CreateGroupHandler;
import com.zhuoan.im.server.handler.FriendsApplyReqHandler;
import com.zhuoan.im.server.handler.FriendsListReqHandler;
import com.zhuoan.im.server.handler.InnerGroupMemberHandler;
import com.zhuoan.im.server.listener.ImDemoGroupListener;
import com.zhuoan.im.server.service.LoginServiceProcessor;
import com.zhuoan.im.webapp.controller.BaseController;
import org.apache.commons.lang3.StringUtils;
import org.jim.common.Const;
import org.jim.common.ImConfig;
import org.jim.common.config.PropertyImConfigBuilder;
import org.jim.common.packets.Command;
import org.jim.server.ImServerStarter;
import org.jim.server.command.CommandManager;
import org.jim.server.command.handler.HandshakeReqHandler;
import org.jim.server.command.handler.LoginReqHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.tio.core.ssl.SslConfig;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 服务启动类
 *
 * @author weixiang.wu
 */
@RestController
@RequestMapping("/")
public class ServerStartController extends BaseController {

    private final static Logger logger = LoggerFactory.getLogger(ServerStartController.class);

    private static ImServerStarter imServerStarter;



    /**
     * Gets config.
     *
     * @return the config
     */
    @RequestMapping("/getServerConfig")
    public String getConfig() {
        Map<String, Object> config = new HashMap<>();
        ImConfig imConfig = new PropertyImConfigBuilder("jim.properties").build();
        config.put("ip", imConfig.getBindIp());
        config.put("port", imConfig.getBindPort());
        return objectToJson(config);
    }

    /**
     * Start server string.
     *
     * @param request the request
     * @return the string
     * @throws IOException the io exception
     */
    @RequestMapping("startServer")
    public String startServer(HttpServletRequest request) {
        if (imServerStarter == null) {
            try {
                // 启动服务
                start();
            } catch (IOException e) {
                logger.error("{}", e);
            }
            logger.info("IP=[" + getIp(request) + "]启动im服务成功");
        }
        return "im服务启动成功";
    }

    /**
     * Stop server string.
     *
     * @param request the request
     * @return the string
     * @throws IOException the io exception
     */
    @RequestMapping("stopServer")
    public String stopServer(HttpServletRequest request) throws IOException {
        if (imServerStarter != null) {
            imServerStarter.stop();
        }
        logger.info("IP=[" + getIp(request) + "]关闭im服务成功");
        return "im服务关闭成功";
    }

    public void start() throws IOException {
        //ImConfig 这个类是j-im 配置启动参数所需要的，比如绑定IP、端口、持久化控制等。
        ImConfig imConfig = new PropertyImConfigBuilder("jim.properties").build();
        /**
         * 设置服务端检测心跳超时时长参数: 保证服务端可以感知到客户端是否还在线，单位是毫秒
         * 如果用户不希望服务端做心跳检查相关工作，请把此值设为0 或负数，
         * 比如这里设置了12000，那服务端会每
         * 隔12000/2=6000 毫秒，也就是每6 秒钟服务端会检测一下客户端消息收发状态，如果这个时间内客户端没有发送心跳，那么服务器端会断开客户端连接并释放所有连接资源
         */
        int heartbeatTimeout = 2000 * 60;
        imConfig.setHeartbeatTimeout(heartbeatTimeout);
        logger.info("#####################设置服务端检测心跳超时时长为{}秒#####################", heartbeatTimeout / 2000);

        //初始化SSL(默认关闭);
        initSsl(imConfig);

        //设置群组监听器，非必须（发退出房间通知）;
        imConfig.setImGroupListener(new ImDemoGroupListener());

        imServerStarter = new ImServerStarter(imConfig);

        /**
         * 添加Command扩展
         */
        addCmdExpand();


        /**
         * 添加新的自定义处理器类
         */
        addNewHandler();

        imServerStarter.start();

    }


    @Resource
    private LoginServiceProcessor loginServiceProcessor;
    @Resource
    private ImWsHandshakeProcessor imWsHandshakeProcessor;

    /**
     * 添加Command扩展
     */
    private void addCmdExpand() {
        //添加握手处理器的扩展;
        HandshakeReqHandler handshakeReqHandler = CommandManager.getCommand(Command.COMMAND_HANDSHAKE_REQ, HandshakeReqHandler.class);
        handshakeReqHandler.addProcessor(imWsHandshakeProcessor);

        //添加登录处理器的扩展;
        LoginReqHandler loginReqHandler = CommandManager.getCommand(Command.COMMAND_LOGIN_REQ, LoginReqHandler.class);
        loginReqHandler.addProcessor(loginServiceProcessor);
    }

    @Resource
    private FriendsApplyReqHandler friendsApplyReqHandler;
    @Resource
    private FriendsListReqHandler friendsListReqHandler;
    @Resource
    private CreateGroupHandler createGroupHandler;
    @Resource
    private InnerGroupMemberHandler innerGroupMemberHandler;

    /**
     * 添加新的自定义处理器类
     */
    private void addNewHandler() {
        try {
            CommandManager.registerCommand(friendsApplyReqHandler);
            CommandManager.registerCommand(friendsListReqHandler);
            CommandManager.registerCommand(createGroupHandler);
            CommandManager.registerCommand(innerGroupMemberHandler);
        } catch (Exception e) {
            logger.error("自定义处理器添加失败", e);
        }

    }

    private static void initSsl(ImConfig imConfig) {
        //开启SSL
        if (Const.ON.equals(imConfig.getIsSSL())) {
            String keyStorePath = PropKit.get("jim.key.store.path");
            String keyStoreFile = keyStorePath;
            String trustStoreFile = keyStorePath;
            String keyStorePwd = PropKit.get("jim.key.store.pwd");
            if (StringUtils.isNotBlank(keyStoreFile) && StringUtils.isNotBlank(trustStoreFile)) {
                SslConfig sslConfig = null;
                try {
                    sslConfig = SslConfig.forServer(keyStoreFile, trustStoreFile, keyStorePwd);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                imConfig.setSslConfig(sslConfig);
            }
        }
    }
}
